#pragma once

#include "Messenging/change/IChangeManager.h"

class ChangeManager : public IChangeManager
{
	struct ObserverPrimaryKey;
	typedef std::multimap<ObserverPrimaryKey, IObserver*> ObserverMap;
	typedef std::pair<ObserverPrimaryKey, IObserver*> ObserverPair;
	typedef std::multimap<viid,IObserver*> DefaultObserverMap;
	typedef std::pair<viid,IObserver*> DefaultObserverPair;

public:
	
	BEGIN_DEFINE_CLASS(CLSID_ChangeManager)
		DEFINE_INTERFACE_ENTRY(IChangeManager)
	END_DEFINE_CLASS()

	ChangeManager();
	virtual ~ChangeManager();

	virtual void EnableAllObserver(bool enable=true);
	virtual bool IsAllObserverEnabled() const;
	virtual void EnableObservers(viid subjectIID, viid interestedObjectIID,bool enable=true);
	virtual bool IsObserversEnabled(viid subjectIID, viid interestedObjectIID) const;

	virtual bool IsObserverRegistered(viid subjectIID, viid interestedObjectIID,IObserver* observer) const;
	virtual void RegisterObserver(viid subjectIID, viid interestedObjectIID,IObserver* observer);
	virtual void UnRegisterObserver(viid subjectIID, viid interestedObjectIID,IObserver* observer);

	virtual void ChangeNotify(viid subjectIID, IObject* subject,const InterestedObjects& interestedObjects,uint32 data=NULL);
	virtual void ChangeNotify(viid subjectIID,viid interestedObjectIID, IObject* subject,const InterestedObjects& interestedObjects,uint32 data=NULL);

private:
	virtual void ChangeNotifyDefault(viid subjectIID,IObject* subject,uint32 data=NULL);
	ObserverMap m_observers;
	DefaultObserverMap m_defaultObservers;
};

AUTO_REGISTER_CLASSMAP_ENTRY(ChangeManager)

//////////////////////////////////////////////////////////////////////////
//inline
struct ChangeManager::ObserverPrimaryKey
{
	viid subjectIID;
	viid interestedObjectIID;

	ObserverPrimaryKey(viid subjectIID,viid interestedObjectIID){this->subjectIID = subjectIID; this->interestedObjectIID = interestedObjectIID;}
	bool operator==(const ObserverPrimaryKey& other) const{return (subjectIID==other.subjectIID) && (interestedObjectIID==other.interestedObjectIID);}
	bool operator!=(const ObserverPrimaryKey& other) const{return (subjectIID!=other.subjectIID) || (interestedObjectIID!=other.interestedObjectIID);}
	bool operator>(const ObserverPrimaryKey& other) const{return (subjectIID>other.subjectIID) && (interestedObjectIID>other.interestedObjectIID);}
	bool operator>=(const ObserverPrimaryKey& other) const{return (subjectIID>=other.subjectIID) && (interestedObjectIID>=other.interestedObjectIID);}
	bool operator<(const ObserverPrimaryKey& other) const{return (subjectIID<other.subjectIID) && (interestedObjectIID<other.interestedObjectIID);}
	bool operator<=(const ObserverPrimaryKey& other) const{return (subjectIID<=other.subjectIID) && (interestedObjectIID<=other.interestedObjectIID);}
};